import {AfterViewInit, Component, OnInit} from '@angular/core';
import {PathItem, PathService} from "../../service/path.service";
import {ActivatedRoute, Router} from "@angular/router";
import {XCrumbNodeClick} from "@ng-nest/ui";
import {FileDesc} from "../../model/file-view";
import {FileViewService} from "../../service/file-view.service";
import {debounceTime, fromEvent} from "rxjs";
import {AppContextService} from "../../service/app-context.service";
import {NzContextMenuService, NzDropdownMenuComponent} from "ng-zorro-antd/dropdown";
import {NzTableSortOrder} from "ng-zorro-antd/table/src/table.types";
import {NzMessageService} from "ng-zorro-antd/message";

// @ts-ignore
@Component({
  selector: 'app-my-file',
  templateUrl: './my-file.component.html',
  styleUrls: ['./my-file.component.less']
})
export class MyFileComponent implements OnInit, AfterViewInit {

  tableLayout = {
    y: '0px',
    // x: '0px'
  }

  multipleChoice = false
  checkedAll = false

  displayType: string = 'list'
  files: FileDesc[] = []
  fileLoading = false

  sortByFilename0 = (f1: FileDesc, f2: FileDesc) => 0
  sortByFilename = (f1: FileDesc, f2: FileDesc, extra: number = 1) => {
    return MyFileComponent.checkPriority(f1, f2, () => {
      return f1.filename.localeCompare(f2.filename) * extra
    })
  }

  sortByFileSize0 = (f1: FileDesc, f2: FileDesc) => 0
  sortByFileSize = (f1: FileDesc, f2: FileDesc, extra: number = 1) => {
    return MyFileComponent.checkPriority(f1, f2, () => {
      return (f1.size - f2.size) * extra
    })
  }

  constructor(
    public pathService: PathService,
    public view: FileViewService,
    private route: ActivatedRoute,
    private contextMenuService: NzContextMenuService,
    public ctx: AppContextService,
    private router: Router,
    private message: NzMessageService
  ) {
  }

  ngOnInit(): void {
    this.onRefreshFileList()
    // 监听多选事件的变化
    this.view.multipleChoiceSubject.subscribe((state: boolean) => {
      this.multipleChoice = state
    })
  }

  ngAfterViewInit(): void {
    this.onWindowResize()
    fromEvent(window, 'resize', {capture: true, passive: true})
      .pipe(debounceTime(100))
      .subscribe(() => {
        this.onWindowResize()
      })
  }

  test0() {
    this.view.toggleMultipleChoice()
  }

  displayFilesize(file: FileDesc): string {
    if (this.view.isDirectory(file)) {
      return '--'
    } else {
      return this.view.humanReadable(file.size)
    }
  }

  onRefreshFileList() {
    const ref = this
    this.fileLoading = true
    this.route.queryParams.subscribe(params => {
      const path = params['path']
      this.pathService.reload(path);
      this.ctx.currentPath = this.pathService.getFileUrl()
      this.view.displayFiles(this.pathService.getFileUrl()).subscribe({
        next(files) {
          ref.files = files
          ref.ctx.currentFiles = files
          ref.doSortByFilename()
        },
        complete() {
          ref.fileLoading = false
        }
      })
    })
  }

  onWindowResize() {
    this.updateTableHeightLimit(
      window.innerHeight
    )
  }

  openMgrContextMenu($event: MouseEvent, menu: NzDropdownMenuComponent) {
    this.contextMenuService.create($event, menu)
  }

  openFileContextMenu($event: MouseEvent, file: FileDesc, menu: NzDropdownMenuComponent) {
    this.ctx.currentFile = file
    this.contextMenuService.create($event, menu)
    $event.stopImmediatePropagation()
  }

  onSelectedFile(file: FileDesc, event: Event) {
    this.contextMenuService.close()
    if (this.ctx.enableMultipleChoice) {
      this.ctx.doSelectedFile(file)
      file.checked = !file.checked
    } else {
      if (!this.view.isDirectory(file)) {
        this.ctx.doSelectedFile(file)
      } else {
        this.ctx.justSelectedFile(file)
        this.ctx.justQuitTopMenu()
      }
    }
    event.stopImmediatePropagation()
  }

  onAccessFile(file: FileDesc) {
    if (this.view.isDirectory(file)) {
      this.gotoFile(file.filename)
    } else {
      this.message.warning('不可打开类型')
    }
  }

  onClickBlank() {
    this.ctx.release()
    this.contextMenuService.close()
  }

  onClickSortBar(event: Event) {
    event.stopImmediatePropagation()
    this.contextMenuService.close()
  }

  onCrumbItemClick(event: XCrumbNodeClick) {
    const path = this.pathService.enter(event.node as PathItem)
    this.gotoPath(path)
  }

  onCheckedFile(file: FileDesc, checked: boolean) {
    file.checked = checked

    let count = 0
    this.files.forEach((file) => {
      if (file.checked) count++
    })
    this.checkedAll = count == this.files.length;
  }

  onCheckedAllFiles(selected: boolean) {
    this.checkedAll = selected
    this.files.forEach((file) => {
      file.checked = selected
    })
  }

  doSortByFilename(type: string | null = null) {
    if (type === null || type === 'descend') {
      this.files = this.files.sort((a, b) => this.sortByFilename(a, b))
    } else {
      this.files = this.files.sort((a, b) => this.sortByFilename(a, b, -1))
    }
  }

  doSortByFileSize(type: string | null = null) {
    if (type === null || type === 'descend') {
      this.files = this.files.sort((a, b) => this.sortByFileSize(a, b))
    } else {
      this.files = this.files.sort((a, b) => this.sortByFileSize(a, b, -1))
    }
  }

  private gotoPath(encodedPath: string) {
    this.router.navigateByUrl(`/home/file?path=${encodedPath}`).then(r => r)
  }

  private gotoFile(filename: string) {
    const path = this.pathService.getFileUrl(filename)
    this.router.navigateByUrl(`/home/file?path=${path}`).then(r => r)
  }

  private static checkPriority(
    f1: FileDesc, f2: FileDesc,
    sort: (a: FileDesc, b: FileDesc) => number
  ): number {
    const p1 = f1.priority
    const p2 = f2.priority
    if (p1 != p2) return p2 - p1
    return sort(f1, f2)
  }

  private updateTableHeightLimit(height: number) {
    // table-body 最大高度限制为:
    // 当前内容区域的高度 - 导航栏高度 - 面包屑高度 - table-head高度 - table-bottom
    const restY = height - 64 - 40 - 47 - 10 - 20
    this.tableLayout = {
      y: `${restY}px`,
      // x: '1180px'
    }
  }

  private static getSortOrder(order?: NzTableSortOrder): number {
    if (order === null || order === 'ascend') {
      return  1
    } else {
      return -1
    }
  }
}
